#include "com.h"
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

com_t com_extern, com_internal, com_subctrl;

uint8_t buff_tx[COM_TX_BUFFER_SIZE];

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
#if ENABLE_OS_SUPPORT
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
#endif
    if (huart->Instance == com_extern.uart->Instance)
    {
#if ENABLE_OS_SUPPORT
        xSemaphoreGiveFromISR(com_extern.rx_complete, &xHigherPriorityTaskWoken);
#else
        com_extern.rx_complete = 1;
#endif
        com_extern.size = Size;
    }
    else if (huart->Instance == com_internal.uart->Instance)
    {
#if ENABLE_OS_SUPPORT
        xSemaphoreGiveFromISR(com_internal.rx_complete, &xHigherPriorityTaskWoken);
#else
        com_internal.rx_complete = 1;
#endif
        com_internal.size = Size;
    }
    else if (huart->Instance == com_subctrl.uart->Instance)
    {
#if ENABLE_OS_SUPPORT
        xSemaphoreGiveFromISR(com_subctrl.rx_complete, &xHigherPriorityTaskWoken);
#else
        com_subctrl.rx_complete = 1;
#endif
        com_subctrl.size = Size;
    }
#if ENABLE_OS_SUPPORT
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
#endif
}

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
#if ENABLE_OS_SUPPORT
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
#endif
    if (huart->Instance == com_extern.uart->Instance)
    {
#if ENABLE_OS_SUPPORT
        xSemaphoreGiveFromISR(com_extern.tx_complete, &xHigherPriorityTaskWoken);
#else
        com_extern.tx_complete = 1;
#endif
    }
    else if (huart->Instance == com_internal.uart->Instance)
    {
#if ENABLE_OS_SUPPORT
        xSemaphoreGiveFromISR(com_internal.tx_complete, &xHigherPriorityTaskWoken);
#else
        com_internal.tx_complete = 1;
#endif
    }
    else if (huart->Instance == com_subctrl.uart->Instance)
    {
#if ENABLE_OS_SUPPORT
        xSemaphoreGiveFromISR(com_subctrl.tx_complete, &xHigherPriorityTaskWoken);
#else
        com_subctrl.tx_complete = 1;
#endif
    }
#if ENABLE_OS_SUPPORT
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
#endif
}

void ComExtern_Init(UART_HandleTypeDef *huart, com_rx_callback_t callback)
{
    com_extern.uart = huart;
    com_extern.callback = callback;
    HAL_UARTEx_ReceiveToIdle_DMA(com_extern.uart, com_extern.payload, COM_RX_BUFFER_SIZE);
#if ENABLE_OS_SUPPORT
    com_extern.tx_complete = xSemaphoreCreateBinary();
    com_extern.rx_complete = xSemaphoreCreateBinary();
    xSemaphoreGive(com_extern.tx_complete);
#else
    com_extern.tx_complete = 1;
#endif
}

void ComExtern_Run()
{
#if ENABLE_OS_SUPPORT
    xSemaphoreTake(com_extern.rx_complete, portMAX_DELAY);
    if (com_extern.callback != NULL)
        com_extern.callback();
#else
    if (com_extern.rx_complete)
    {
        if (com_extern.callback != NULL)
            com_extern.callback();

        com_extern.rx_complete = 0;
    }
#endif
    HAL_UARTEx_ReceiveToIdle_DMA(com_extern.uart, com_extern.payload, COM_RX_BUFFER_SIZE);
}

void ComExtern_Print(const char *fmt, ...)
{
#if ENABLE_OS_SUPPORT
    xSemaphoreTake(com_extern.tx_complete, portMAX_DELAY);
#else
    while (!com_extern.tx_complete)
        continue;
    com_extern.tx_complete = 0;
#endif
    va_list args;
    va_start(args, fmt);
    vsprintf((char *)buff_tx, fmt, args);
    HAL_UART_Transmit_DMA(com_extern.uart, buff_tx, strlen((char *)buff_tx));
}

void ComExtern_Send(uint8_t *data, uint16_t size)
{
#if ENABLE_OS_SUPPORT
    xSemaphoreTake(com_extern.tx_complete, portMAX_DELAY);
#else
    while (!com_extern.tx_complete)
        continue;
    com_extern.tx_complete = 0;
#endif
    HAL_UART_Transmit_DMA(com_extern.uart, data, size);
}

void ComInternal_Init(UART_HandleTypeDef *huart, com_rx_callback_t callback)
{
    com_internal.uart = huart;
    com_internal.callback = callback;
    HAL_UARTEx_ReceiveToIdle_DMA(com_internal.uart, com_internal.payload, COM_RX_BUFFER_SIZE);
#if ENABLE_OS_SUPPORT
    com_internal.tx_complete = xSemaphoreCreateBinary();
    com_internal.rx_complete = xSemaphoreCreateBinary();
    xSemaphoreGive(com_internal.tx_complete);
#else
    com_internal.tx_complete = 1;
#endif
}

void ComInternal_Run()
{
#if ENABLE_OS_SUPPORT
    xSemaphoreTake(com_internal.rx_complete, portMAX_DELAY);
    if (com_internal.callback != NULL)
        com_internal.callback();
#else
    if (com_internal.rx_complete)
    {
        if (com_internal.callback != NULL)
            com_internal.callback();
        com_internal.rx_complete = 0;
    }
#endif
    HAL_UARTEx_ReceiveToIdle_DMA(com_internal.uart, com_internal.payload, COM_RX_BUFFER_SIZE);
}

void ComInternal_Send(uint8_t *data, uint16_t size)
{
#if ENABLE_OS_SUPPORT
    xSemaphoreTake(com_internal.tx_complete, portMAX_DELAY);
#else
    while (!com_internal.tx_complete)
        continue;
    com_internal.tx_complete = 0;
#endif
    HAL_UART_Transmit_DMA(com_internal.uart, data, size);
}

void ComSubCtrl_Init(UART_HandleTypeDef *huart, com_rx_callback_t callback)
{
    com_subctrl.uart = huart;
    com_subctrl.callback = callback;
    HAL_UARTEx_ReceiveToIdle_DMA(com_subctrl.uart, com_subctrl.payload, COM_RX_BUFFER_SIZE);
#if ENABLE_OS_SUPPORT
    com_subctrl.tx_complete = xSemaphoreCreateBinary();
    com_subctrl.rx_complete = xSemaphoreCreateBinary();
    xSemaphoreGive(com_subctrl.tx_complete);
#else
    com_subctrl.tx_complete = 1;
#endif
}

void ComSubCtrl_Run()
{
#if ENABLE_OS_SUPPORT
    xSemaphoreTake(com_subctrl.rx_complete, portMAX_DELAY);
    if (com_subctrl.callback != NULL)
        com_subctrl.callback();
#else
    if (com_subctrl.rx_complete)
    {
        if (com_subctrl.callback != NULL)
            com_subctrl.callback();

        com_subctrl.rx_complete = 0;
    }
#endif
    HAL_UARTEx_ReceiveToIdle_DMA(com_subctrl.uart, com_subctrl.payload, COM_RX_BUFFER_SIZE);
}

void ComSubCtrl_Send(uint8_t *data, uint16_t size)
{
#if ENABLE_OS_SUPPORT
    xSemaphoreTake(com_subctrl.tx_complete, portMAX_DELAY);
#else
    while (!com_subctrl.tx_complete)
        continue;
    com_subctrl.tx_complete = 0;
#endif
    HAL_UART_Transmit_DMA(com_subctrl.uart, data, size);
}